package com.tuanzi.loan.business.repository.statistics.impl;


import com.google.common.collect.Maps;
import com.tuanzi.loan.business.entity.statistics.api.ApiFlowStatSql;
import com.tuanzi.loan.business.repository.statistics.ApiFlowStatRepository;
import com.tuanzi.loan.vo.request.statistics.api.ApiFlowStatSearchRequest;
import com.tuanzi.loan.vo.response.statistics.api.ApiFlowStatSearchResponse;
import com.tuanzi.server.loan_base.util.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.stereotype.Repository;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;


@Slf4j
@Repository
public class ApiFlowStatRepositoryImpl implements ApiFlowStatRepository {

    @Autowired
    private Environment environment;
//    @Autowired
//    private ApplicationContext applicationContext;


    @Override
    public Page<ApiFlowStatSearchResponse> list(ApiFlowStatSearchRequest searchRequest, Pageable pageable) {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("org.postgresql.Driver");
        dataSource.setUrl(environment.getProperty("maxcompute.url"));
        dataSource.setUsername(environment.getProperty("maxcompute.username"));
        dataSource.setPassword(environment.getProperty("maxcompute.password"));
        NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);


//        Resource resource = applicationContext.getResource("classpath:maxcompute-sql/api-statistics.sql");
//        Resource countResource = applicationContext.getResource("classpath:maxcompute-sql/api-statistics-count.sql");
//        log.info("API-STATISTICS resource : {}", resource);
//        log.info("API-STATISTICS countResource : {}", countResource);

        String sql = ApiFlowStatSql.apiStatisticsSql;
        String countSql = ApiFlowStatSql.apiStatisticsCountSql;

//        try {
//            sql = FileUtils.readFileToString(resource.getFile(), StandardCharsets.UTF_8);
//            countSql = FileUtils.readFileToString(countResource.getFile(), StandardCharsets.UTF_8);
//        } catch (Exception e) {
//            log.error(e.getMessage(), e);
//        }

        if(CollectionUtils.isEmpty(searchRequest.getGroupByConditions())) {
            sql = StringUtils.replace(sql, "{replace_select_field}", ",daytime,product_name,api_id");
            sql = StringUtils.replace(sql, "{replace_group_by_field}", " GROUP BY daytime,product_name,api_id ");
            countSql = StringUtils.replace(countSql, "{replace_group_by_field}", " GROUP BY daytime,product_name,api_id ");
        }else{
            sql = StringUtils.replace(sql, "{replace_select_field}", ",daytime" + searchRequest.getGroupByConditions().parallelStream().map(x -> ","+ x).collect(Collectors.joining()));
            sql = StringUtils.replace(sql, "{replace_group_by_field}", " GROUP BY daytime," + searchRequest.getGroupByConditions().parallelStream().collect(Collectors.joining(",")));
            countSql = StringUtils.replace(countSql, "{replace_group_by_field}", " GROUP BY daytime," + searchRequest.getGroupByConditions().parallelStream().collect(Collectors.joining(",")));
        }

        sql = replaceSearchByApi(sql,searchRequest.getApiId());
        sql = replaceSearchByProduct(sql,searchRequest.getParentName());
        countSql = replaceSearchByApi(countSql,searchRequest.getApiId());
        countSql = replaceSearchByProduct(countSql,searchRequest.getParentName());

        log.info("API-STATISTICS SQL2 : {}", sql);
        log.info("API-STATISTICS COUNT_SQL2 : {}", countSql);

        Map<String, Object> parameters = Maps.newHashMap();
        parameters.put("startDate", DateUtils.formatDateToYyyyMMdd(searchRequest.getStartTime()));
        parameters.put("endDate", DateUtils.formatDateToYyyyMMdd(searchRequest.getEndTime()));
        parameters.put("limit", pageable.getPageSize());
        parameters.put("offset", pageable.getOffset());

        List<ApiFlowStatSearchResponse> response = jdbcTemplate.query(sql, parameters, new RowMapper<ApiFlowStatSearchResponse>() {
            @Override
            public ApiFlowStatSearchResponse mapRow(ResultSet resultSet, int i) throws SQLException {
                ApiFlowStatSearchResponse response = new ApiFlowStatSearchResponse();

                response.setDate(resultSet.getString("daytime"));
                response.setActiveUv(resultSet.getLong("active_num"));
                response.setClickDetailNewUv(resultSet.getLong("click_detail_new_uv"));
                response.setViewDetailNewUv(resultSet.getLong("view_detail_new_uv"));
                response.setViewApiUv(resultSet.getLong("view_api_uv"));
                response.setPrePushUv(resultSet.getLong("pre_push_uv"));
                response.setPushUv(resultSet.getLong("push_uv"));
                response.setPregrantUv(resultSet.getLong("pregrant_uv"));
                response.setLoanUv(resultSet.getLong("loan_uv"));
                if(CollectionUtils.isEmpty(searchRequest.getGroupByConditions())||searchRequest.getGroupByConditions().contains("api_id")){
                    response.setApiId(resultSet.getString("api_id"));
                }
                if(CollectionUtils.isEmpty(searchRequest.getGroupByConditions())||searchRequest.getGroupByConditions().contains("product_name")){
                    response.setProductName(resultSet.getString("product_name"));
                }

                return response;
            }
        });

        Long count = jdbcTemplate.queryForObject(countSql, parameters, (resultSet, i) -> {
            long count1 = resultSet.getLong("countNumber");
            return count1;
        });

        return new PageImpl(response, pageable, count);
    }

    private String replaceSearchByApi(String sql, List<String> apiIds) {
        return CollectionUtils.isNotEmpty(apiIds)
                ? StringUtils.replace(sql, "{replace_search_by_api}",
                "AND api_id IN (" + apiIds.parallelStream().map(x -> "'"+ x +"'").collect(Collectors.joining(","))+")")
                : StringUtils.replace(sql, "{replace_search_by_api}", "");
    }

    private String replaceSearchByProduct(String sql, List<String> products) {
        return CollectionUtils.isNotEmpty(products)
                ? StringUtils.replace(sql, "{replace_search_by_product}",
                " AND product_name IN (" + products.parallelStream().map(x -> "'"+ x +"'").collect(Collectors.joining(","))+")")
                : StringUtils.replace(sql, "{replace_search_by_product}", "");
    }
}
